#version 330

struct Attenuation{
    float constant;
    float linear;
    float exponent;
};

struct PointLight{
    vec3 color;

// 相机坐标系中的位置
    vec3 position;
    float intensity;
    Attenuation att;
};

struct Material{
    vec4 ambient;
    vec4 diffuse;
    vec4 specular;
    int hasTexture;
    float reflectance;
};

in vec2 v_texCoord;
in vec3 mvNormal;
in vec3 mvVertexPos;

out vec4 fragColor;
uniform sampler2D texture_sampler;

uniform vec3 ambientLight;
uniform float specularPower;

uniform Material material;
uniform PointLight pointLight;

// 相当于 物体材质
vec4 ambientC;
vec4 diffuseC;
vec4 specularC;

void setupColor(Material material,vec2 texCoord){
    if(material.hasTexture == 1){
        ambientC = texture(texture_sampler,texCoord);
        diffuseC = ambientC;
        specularC = ambientC;
    }else{
        ambientC = material.ambient;
        diffuseC = material.diffuse;
        specularC = material.specular;
    }
}


vec4 calPointLight(PointLight light,vec3 position,vec3 normal){
    vec4 diffuseColor = vec4(0.0);
    vec4 speceColor = vec4(0.0);

    // diffuse Light
    vec3  light_direction = light.position - position;
    vec3  to_light_source = normalize(light_direction);
    float diffuseFactor = max(dot(normal,to_light_source),0.0); // 漫反射系数
    diffuseColor = diffuseC * vec4(light.color,1.0) * light.intensity * diffuseFactor;

    // specular light
    vec3 camera_direction = normalize(-position);
    vec3 from_light_source = -to_light_source;
    vec3 reflected_light = normalize(reflect(from_light_source,normal));
    float specularFactor = dot(camera_direction,reflected_light);
    if(specularFactor > 0.0){
        specularFactor = pow(specularFactor,specularPower);  //  镜面反射系数
        speceColor = specularC * vec4(light.color,1.0) * material.reflectance * specularFactor;
    }

    // attenuation
    float distance = length(light_direction);
    float attInv = light.att.constant + light.att.linear * distance + light.att.exponent * distance * distance;
    return (diffuseColor + speceColor) / attInv;
}


void main()
{
    setupColor(material,v_texCoord);
    vec4 diffuseSpecularComp = calPointLight(pointLight,mvVertexPos,mvNormal);
    fragColor = ambientC * vec4(ambientLight,1.0) + diffuseSpecularComp;
}